/**
 * @file Controller.cpp
 * @author enemy1205 (enemy1205@qq.com)
 * @brief 控制器管理类
 * @date 2021-09-11
 */
#include "Controller.h"

using namespace cv;

void operator<<(std::ostream &os, DataStruct dataStruct) {
//    os << "shoot_mode:" << (int) dataStruct.shoot_mode << endl;
//    os << "Flag:" << (int) dataStruct.Flag << endl;
    os << "pitch:" << dataStruct.pitch << endl;
    os << "yaw:" << dataStruct.yaw << endl;
}

/**
 * @brief 控制器构造函数,初始化命令行
 * @param argv 命令行输入指令
 */
Controller::Controller(int argc, char *argv[]) {
    this->cmd.Init(argc, argv);
    //初始化检测模式
    this->_detectId = -1;
    //初始化相机模式
    this->_cameraId = -1;
}

/**
 * @brief 相机初始化
 * @param _id 识别模式
 */
void Controller::initCamera(int _id) {
    if (this->cmd.input().empty()) {
        capture = std::make_unique<RMVideoCapture>();
        // 找到相机则初始化相机参数
        if (this->capture->isOpened()) {
            // init - 曝光度
            switch (_id) {
                case 0:
                    this->capture->set(CAP_PROP_EXPOSURE, cameraParam.cam_exposure);
                    break;
                case 1://打符
                    this->capture->set(CAP_PROP_EXPOSURE, 450);
                    break;
                default:
                    this->capture->set(CAP_PROP_EXPOSURE, cameraParam.cam_exposure);
                    break;
            }
            // init - 对比度
            this->capture->set(CAP_PROP_CONTRAST, cameraParam.cam_contrast);
            // init - Gamma
            this->capture->set(CAP_PROP_GAMMA, cameraParam.cam_gamma);
            // init - 设置颜色增益
            this->capture->set(CAP_PROP_XI_WB_KB, cameraParam.cam_Bgain);
            this->capture->set(CAP_PROP_XI_WB_KG, cameraParam.cam_Ggain);
            this->capture->set(CAP_PROP_XI_WB_KR, cameraParam.cam_Rgain);
            // init - 启用颜色增益
            this->capture->set(CAP_PROP_AUTO_WB, 0);
        }
    } else capture = std::make_unique<VideoCapture>(this->cmd.input());
}

void Controller::setCamera() {
    // 获取相机模式
    uint8_t tmp_camId;
    // 判断是否切换相机
    switch (this->_mode) {
        case 0U:
            tmp_camId = ARMOR_DETECT;
            break;
        case 1U:
            tmp_camId = RUNE_DETECT;
            break;
        default:
            tmp_camId = ARMOR_DETECT;
            break;
    }
    /////如果上帧相机ID不等于输入相机状态，先reset释放，再初始化
    if (this->_cameraId != tmp_camId) {
        this->capture.reset();
        this->initCamera(tmp_camId);
        this->_cameraId = tmp_camId;
    }
}

/**
 * @brief 检测模式设置,实时更新
 */
void Controller::setDetector() {
    // 获取检测模式
    uint8_t tmp_detId;
    switch (this->_mode) {
        /////电脑端发送指令
//        case 0U:
//        case 1U:
//            tmp_detId = ARMOR_DETECT;
//            break;
//        case 2U:
//            tmp_detId = RUNE_DETECT;
//            break;
//        default:
//            tmp_detId = ARMOR_DETECT;
//            break;
        /////调试时指令
        case 0:
            tmp_detId = ARMOR_DETECT;
            break;
        case 1:
            tmp_detId = RUNE_DETECT;
            break;
        default:
            tmp_detId = ARMOR_DETECT;
            break;
    }
    // 判断是否切换检测器
    if (this->_detectId != tmp_detId) {
        switch (tmp_detId) {
            case ARMOR_DETECT:
                visualControl = std::make_unique<AutoAim>();
                break;
            case RUNE_DETECT:
                visualControl = std::make_unique<BuffActivate>();
                break;
            default:
                visualControl = std::make_unique<AutoAim>();
                break;
        }
        this->_detectId = tmp_detId;
    }
}

/**
 * @brief 执行函数(主函数)
 */
bool Controller::execute() {
    startTime = clock();//开始计时
    if (!this->port.isOpen()) {
        logger.WARNING("串口异常");
    }
    //传入参数：从head到tail的电控发送来的数据 ,filter:读取串口数据赋值给具体参数
    gyro_data = port_manager.filter(this->port.readStruct<GyroData>(0x44, 0x55));//步兵接受数据类型
//    cout<<"pitch_speed"<<gyro_data.pitchSpeed<<endl;
//    cout<<"yaw_speed"<<gyro_data.yawSpeed<<endl;
//    this->setId(Other_param.init_detect_mode);//视频测试指定模式
    this->setId(gyro_data.RegionMode);//接受操作手指令
    this->setCamera();
    this->setDetector();
    Mat img;
    capture->read(img);
    //多帧为空退出程序
    if (img.empty()) {
        logger.WARNING("未读取到该帧图像");
        break_record++;
        if (break_record >= 2)return false;
        else return true;
    }
    //视觉更新每一帧所有信息
//    try {
    this->port_manager.send(this->send_data, this->visualControl->updateFrame(img, gyro_data));
//    cout<<send_data;
//    }
//    catch (...)
//    {
//        this->send_data.pitch = 0.f;
//        this->send_data.yaw = 0.f;
//        this->logger.WARNING("数据发送异常");
//    }
    //写入成电控能够读取的数据格式
    this->port.writeStruct(send_data);
    //展示绘制窗口
    if (cmd.show()) visualControl->show();
    endTime = clock();//结束计时
    //打印每帧处理用时
    if (cmd.time())
        cout << float(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
    if (visualControl->exit())return false;
    return true;
}

/**
 * @brief 析构释放指针
 */
Controller::~Controller() {
    capture->release();
    capture = nullptr;
    visualControl = nullptr;
}

/**
 * @brief 调试接口
 */
void Controller::debug() {
    Mat img = imread(cmd.input());
    visualControl = std::make_unique<AutoAim>();
    visualControl->updateFrame(img, gyro_data);
    if (cmd.show()) visualControl->show();
    if (visualControl->exit())return;
}